// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_CORE_NATIVEWINDOWWIN_HPP
#define OUZEL_CORE_NATIVEWINDOWWIN_HPP

#include <set>
#pragma push_macro("WIN32_LEAN_AND_MEAN")
#pragma push_macro("NOMINMAX")
#ifndef WIN32_LEAN_AND_MEAN
#  define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#  define NOMINMAX
#endif
#include <Windows.h>
#pragma pop_macro("WIN32_LEAN_AND_MEAN")
#pragma pop_macro("NOMINMAX")

#include "core/NativeWindow.hpp"

namespace ouzel
{
    class EngineWin;

    class NativeWindowWin final: public NativeWindow
    {
        friend EngineWin;
    public:
        NativeWindowWin(const std::function<void(const Event&)>& initCallback,
                        const Size2U& newSize,
                        bool newResizable,
                        bool newFullscreen,
                        bool newExclusiveFullscreen,
                        const std::string& newTitle,
                        bool newHighDpi);
        ~NativeWindowWin();

        void executeCommand(const Command& command) final;

        void close();

        void setSize(const Size2U& newSize);
        void setFullscreen(bool newFullscreen);
        void setTitle(const std::string& newTitle);
        void bringToFront();
        void show();
        void hide();
        void minimize();
        void maximize();
        void restore();

        void handleResize(const Size2U& newSize);
        void handleMove();
        void handleActivate(WPARAM wParam);
        void handleShowWindow(BOOL shown);
        void handleMinimize();
        void handleMaximize();
        void handleRestore();
        void handleKey(UINT message, WPARAM wParam, LPARAM lParam);
        void handleMouseMove(LPARAM lParam);
        void handleMouseButton(UINT message, WPARAM wParam, LPARAM lParam);
        void handleMouseWheel(UINT message, WPARAM wParam, LPARAM lParam);
        void handleTouch(WPARAM wParam, LPARAM lParam);

        inline auto getNativeWindow() const noexcept { return window; }
        void addAccelerator(HACCEL accelerator);
        void removeAccelerator(HACCEL accelerator);

        inline auto getMonitor() const noexcept { return monitor; }

    private:
        void switchFullscreen(bool newFullscreen);

        ATOM windowClass = 0;
        HWND window = nullptr;
        DWORD windowStyle = 0;
        DWORD windowExStyle = 0;
        DWORD windowWindowedStyle = 0;
        DWORD windowFullscreenStyle = 0;
        HMONITOR monitor = nullptr;

        int windowX = 0;
        int windowY = 0;
        int windowWidth = 0;
        int windowHeight = 0;

        std::set<HACCEL> accelerators;
    };
}

#endif // OUZEL_CORE_NATIVEWINDOWWIN_HPP
